(function(){with(HappyFarm.util){

HappyFarm.GlobalData = {
    _shift: 0,
    get ServerTime() {
        return Math.floor((Date.now() - this._shift)/1000);
    },
    exp2level: function(exp) {
        return Math.sqrt((exp+25)/100)-0.5;
    },
    level2exp: function(level) {
        return 100 * level * (level + 1);
    },
    get Exp() {
        return this._userlist[this.uId].exp;
    },
    get Level() {
        return Math.floor(this.exp2level(this.Exp));
    },
    get Rank() {
        var exp = this.Exp;
        return this.Friends.reduce(function(a, friend){
            if(friend.exp > exp) return a+1;
            else return a;
        }, 1);
    },
    get References() {
        var crops = this.Crops;
        var seeds = this.Seeds;
        var level = this.Level;
        var units = seeds.map(function(seed){
            var totalTime = (parseInt(seed.growthCycle)+(parseInt(seed.maturingTime)-1)*(parseInt(seed.growthCycle)-parseInt(crops[seed.cId].cropGrow[2])))/3600;
            return [(parseInt(seed.expect)-parseInt(seed.price))/totalTime, (parseInt(seed.cropExp)*parseInt(seed.maturingTime))/totalTime];
        });
        var valuable = [i for(i in seeds)];
        var expable = [i for(i in seeds)];
        valuable.sort(function(c1, c2){
            var l1 = parseInt(seeds[c1].cLevel);
            var l2 = parseInt(seeds[c2].cLevel);
            var u1 = units[c1][0];
            var u2 = units[c2][0];
//            if(l1>level) u1 -= 999;
//            if(l2>level) u2 -= 999;
            return -(u1-u2);
        });
        expable.sort(function(c1, c2){
            var l1 = parseInt(seeds[c1].cLevel);
            var l2 = parseInt(seeds[c2].cLevel);
            var u1 = units[c1][1];
            var u2 = units[c2][1];
//            if(l1>level) u1 -= 999;
//            if(l2>level) u2 -= 999;
            return -(u1-u2);
        });
        return [units, valuable, expable];
    },
    //Interface for HFAPI
    setCropsResult: function(doc) {
        if(doc.errorType.toString() != '') {
            log('ERROR', 'Failed to update crop information: '+doc.errorContent.toString());
            return;
        }
        var _crops = {};
        var cropList = doc.crops.crop;
        for each(var crop in cropList) {
            _crops[crop.@id] = {
                cId: parseInt(crop.@id),
                enName: crop.@className,
                cropGrow: [parseInt(n) for each(n in crop.cropGrow.@value.split(','))]
            };
        }
        this._crops = _crops;
        this._cropsTime = new Date();
        log('LOG', 'Succeded to update crop infomation');
    },
    get Crops() {
        return this._crops;
    },
    get CropsTime() {
        return this._cropsTime;
    },
    //Interface for HFAPI
    setSeedsResult: function(seeds) {
        if(seeds.errorType) {
            log('ERROR', 'Failed to update seed information: '+seeds.errorContent);
            return;
        }
        this._seeds = seeds;
        this._seedsTime = new Date();
        log('LOG', 'Succeded to update seed information');
    },
    get Seeds() {
        return this._seeds;
    },
    //Interface for HFAPI
    setFriendResult: function(friends) {
        if(friends.errorType) {
            log('ERROR', 'Failed to update friend information: '+friends.errorContent);
            return;
        }
        this._friends = friends;
        this._friendsTime = new Date();
        log('LOG', 'Succeded to update friend information');
    },
    get Friends() {
        return this._friends;
    },
    _userlist: {},
    //Interface for HFAPI
    setRunResult: function(ownerId, user) {
        if(user.errorType) {
            log('ERROR', 'Failed to update user information for '+(ownderId?ownderId:'me')+': '+user.errorContent);
            return;
        }
        var uId = ownerId || user.user.uId;
        var farmlandStatus = [this._parseFieldData(field)
                    for each(field in user.farmlandStatus)];
        var exp = parseInt(user.exp);

        this._userlist[uId] = {
            uId: uId,
            exp: exp,
            farmlandStatus: farmlandStatus,
            runTime: new Date()
        };
        if(user.serverTime) {
            this._shift = (Date.now() - parseInt(user.serverTime.time) * 1000);
        }
        if(!ownerId) {
            this._uId = user.user.uId;
        }
        log('LOG', 'Succeded to update user information for '+uId);
    },
    get uId() {
        return this._uId;
    },
    getUser: function(uid) {
        return this._userlist[uid];
    },
    getUserTime: function(uid) {
        return this._userlist[uid].runTime;
    },
    get AllUsers() {
        return this._userlist;
    },
    get EncodeKey(){
        return getPref('encode_key', '15l3h4kh');
    },
    setEncodeKeyResult: function(key){
        setPref('encode_key', key);
    },
    setWaterResult: function(ownerId, place, data) {
        if(data.errorType) {
            log('ERROR', 'Failed to water for uId('+ownerId+'), place('+place+'): '+data.errorContent);
            return;
        }
        log('LOG', 'Succeded to water for uId('+ownerId+'), place('+place+')');
    },
    setSprayingResult: function(ownerId, place, data) {
        if(data.errorType) {
            log('ERROR', 'Failed to spraying for uId('+ownerId+'), place('+place+'): '+data.errorContent);
            return;
        }
        log('LOG', 'Succeded to spraying for uId('+ownerId+'), place('+place+')');
    },
    setClearWeedResult: function(ownerId, place, data) {
        if(data.errorType) {
            log('ERROR', 'Failed to clear weed uId('+ownerId+'), place('+place+'): '+data.errorContent);
            return;
        }
        log('LOG', 'Succeded to clear weed uId('+ownerId+'), place('+place+')');
    },
    setHarvestResult: function(ownerId, place, data) {
        if(data.errorType) {
            log('ERROR', 'Failed to harvest for uId('+ownerId+'), place('+place+'): '+data.errorContent);
            return;
        }
        log('LOG', 'Succeded to harvest for uId('+ownerId+'), place('+place+')');
    },
    setPlantingResult: function(place, cId, data) {
        if(data.errorType) {
            log('ERROR', 'Failed to plant. place('+place+'), cId('+cId+'): '+data.errorContent);
            return;
        }
            log('ERROR', 'Succeded to plant. place('+place+'), cId('+cId+'): '+data.errorContent);
    },
    matureTime: function(cId, plantTime, state, harvestTimes) {
        var state = this.idState(cId, plantTime, state, harvestTimes);
        if(cId == 0 || state == 7) return -1;
        var growTimes = this.Crops[cId].cropGrow;
        return plantTime + growTimes[4];

    },
    idState: function(cId, plantTime, state, harvestTimes, sTimeOff){
        if (cId == 0) {
            return 0;
        }
        if (state == 7) {
            return 7;
        }
        var sTime = this.ServerTime + (sTimeOff || 0);
        var cTime = sTime - plantTime;
        var growTimes = this.Crops[cId].cropGrow;
        var i = growTimes.length-1;
        while (i >= 0) {
            if (cTime >= growTimes[i]) {
                state = i + 1;
                if (harvestTimes > 0) {
                    if (state < 3) {
                        return 3;
                    }
                }
                return i + 1;
            }
            i--;
        }
        return 0;
    },
    //@private
    _parseFieldData: function(elem){
        var d = {
            cId:        elem.a,
            state:      elem.b,
            oldWeed:    elem.c,
            oldPest:    elem.d,
            oldHumidity:elem.e,
            weed:       elem.f,
            pest:       elem.g,
            humidity:   elem.h,
            health:     elem.i,
            harvestTimes:   elem.j,
            output:     elem.k,
            min:        elem.l,
            leavings:   elem.m,
            thieves:    elem.n,
            //fertize
            actions:    elem.p,
            plantTime:  elem.q,
            updateTime: elem.r,
            pId:        elem.s,
            nPh:        elem.t,
            mPh:        elem.u
        };
        d.step = this.idState(d.cId, d.plantTime, d.state, d.harvestTimes);
        d.fertilize = (elem.o == d.step + 1);
        return d;
    }
};

}})();
